package cn.zyjblogs.filter;

import cn.zyjblogs.config.replay.AntiReplayProperties;
import cn.zyjblogs.crypto.sm3.SM3;
import cn.zyjblogs.exception.AntiReplayException;
import com.alibaba.fastjson2.JSON;
import com.alibaba.nacos.common.utils.ConvertUtils;
import lombok.extern.log4j.Log4j2;
import org.springframework.http.HttpHeaders;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.util.MultiValueMap;

import java.util.Map;

/**
 * @author zhuyijun
 */
@Log4j2
public class SignatureValidator {

    public static SignatureWorker builder() {
        return new SignatureWorker();
    }

    public static class SignatureWorker {

        private AntiReplayProperties antiReplayProperties;
        /**
         * 请求标识
         */
        private String nonce;
        /**
         * 请求时间
         */
        private Long timestamp;

        private String queryParams;
        /**
         * 请求参数
         */
        private Map<String, Object> params;
        /**
         * 请求的签名
         */
        private String sign;


        public SignatureWorker nonce(String nonce) {
            this.nonce = nonce;
            return this;
        }

        public SignatureWorker antiReplayProperties(AntiReplayProperties antiReplayProperties) {
            this.antiReplayProperties = antiReplayProperties;
            return this;
        }

        public SignatureWorker timestamp(Long timestamp) {
            this.timestamp = timestamp;
            return this;
        }

        public SignatureWorker params(Map<String, Object> parameterMap) {
            this.params = parameterMap;
            return this;
        }

        public SignatureWorker sign(String sign) {
            this.sign = sign;
            return this;
        }


        public SignatureWorker queryParams(MultiValueMap<String, String> queryParams) {
            this.queryParams = JSON.toJSONString(queryParams);
            return this;
        }

        public SignatureWorker data(AntiReplayProperties antiReplayProperties, ServerHttpRequest request) {
            HttpHeaders headers = request.getHeaders();
            String nonce = headers.getFirst(antiReplayProperties.getNonce());
            String timestamp = headers.getFirst(antiReplayProperties.getTimestamp());
            String sign = headers.getFirst(antiReplayProperties.getSign());
            return this.nonce(nonce)
                    .antiReplayProperties(antiReplayProperties)
                    .timestamp(ConvertUtils.toLong(timestamp))
                    .queryParams(request.getQueryParams())
                    .sign(sign);
        }


        public void execute() {
            if (Boolean.FALSE.equals(antiReplayProperties.getSignEnabled())) {
                return;
            }
            String digest = this.nonce + this.timestamp + this.queryParams;
            if (!SM3.verify(digest, this.sign)) {
                if (log.isDebugEnabled()) {
                    log.debug("数据签名验证未通过, 传入签名:[ {} ], 生成签名:[ {} ]", sign, digest);
                }
                throw new AntiReplayException("数据签名验证未通过");
            }
        }

    }
}
